/********************************************************************************************************
 * @file	tutility.h
 *
 * @brief	for TLSR chips
 *
 * @author	telink
 * @date	Sep. 30, 2010
 *
 * @par     Copyright (c) 2010, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *          All rights reserved.
 *
 *          Licensed under the Apache License, Version 2.0 (the "License");
 *          you may not use this file except in compliance with the License.
 *          You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 *          Unless required by applicable law or agreed to in writing, software
 *          distributed under the License is distributed on an "AS IS" BASIS,
 *          WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *          See the License for the specific language governing permissions and
 *          limitations under the License.
 *
 *******************************************************************************************************/
#pragma once
#include "types.h"
#ifndef WIN32 
#define abs(a)   (((a)>0)?((a)):(-(a)))

#define cat2(i,j)       i##j
#define cat3(i,j,k)     i##j##k
#endif

#ifndef min
#define min(a,b)	((a) < (b) ? (a) : (b))
#endif

#ifndef min2
#define min2(a,b)	((a) < (b) ? (a) : (b))
#endif

#ifndef min3
#define min3(a,b,c)	min2(min2(a, b), c)
#endif

#ifndef max2
#define max2(a,b)	((a) > (b) ? (a): (b))
#endif

#ifndef max3
#define max3(a,b,c)	max2(max2(a, b), c)
#endif

#define SIZEOF_MEMBER(s, m)     (sizeof(((s *)0)->m))
#define OFFSETOF(s, m) 			((unsigned int) &((s *)0)->m)
#ifndef WIN32
#define CONTAINER_OF(ptr, type, member) ({              \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - OFFSETOF(type,member) );}) 
#else
#define CONTAINER_OF(ptr, type, member)  ((type *)((char *)ptr - OFFSETOF(type,member)))	
#endif
#define ROUND_INT(x, r)			(((x) + (r) - 1) / (r) * (r))
#define ROUND_TO_POW2(x, r)		(((x) + (r) - 1) & ~((r) - 1))

//  direct memory access 
#define U8_GET(addr)			(*(volatile unsigned char  *)(addr))
#define U16_GET(addr)			(*(volatile unsigned short *)(addr))
#define U32_GET(addr)			(*(volatile unsigned int  *)(addr))

#define U8_SET(addr, v)			(*(volatile unsigned char  *)(addr) = (unsigned char)(v))
#define U16_SET(addr, v)		(*(volatile unsigned short *)(addr) = (unsigned short)(v))
#define U32_SET(addr, v)		(*(volatile unsigned int  *)(addr) = (v))

#define U8_INC(addr)			U8_GET(addr) += 1
#define U16_INC(addr)			U16_GET(addr) += 1
#define U32_INC(addr)			U32_GET(addr) += 1

#define U8_DEC(addr)			U8_GET(addr) -= 1
#define U16_DEC(addr)			U16_GET(addr) -= 1
#define U32_DEC(addr)			U32_GET(addr) -= 1

#define U8_CPY(addr1,addr2)		U8_SET(addr1, U8_GET(addr2))
#define U16_CPY(addr1,addr2)	U16_SET(addr1, U16_GET(addr2))
#define U32_CPY(addr1,addr2)	U32_SET(addr1, U32_GET(addr2))

#define MAKE_U16(h,l) 			((unsigned short)(((h) << 8) | (l)))
#define MAKE_U32(a,b,c,d)		((unsigned int)(((a) << 24) | ((b) << 16) | ((c) << 8) | (d)))

#define BOUND(x, l, m)			((x) < (l) ? (l) : ((x) > (m) ? (m) : (x)))
#define SET_BOUND(x, l, m)		((x) = BOUND(x, l, m))
#define BOUND_INC(x, m)			do{++(x); (x) = (x) < (m) ? (x) :0;} while(0)
#define BOUND_INC_POW2(x, m)	do{								\
									STATIC_ASSERT_POW2(m);		\
									(x) = ((x)+1) & (m-1);		\
								}while(0)

#define IS_POWER_OF_2(x)		(!(x & (x-1)))
#define IS_LITTLE_ENDIAN 		(*(unsigned short*)"\0\xff" > 0x100) 

#define IMPLIES(x, y) 			(!(x) || (y))

// x > y ? 1 : (x ==y : 0 ? -1)
#define COMPARE(x, y) 			(((x) > (y)) - ((x) < (y)))
#define SIGN(x) 				COMPARE(x, 0)

// better than xor swap:  http://stackoverflow.com/questions/3912699/why-swap-with-xor-works-fine-in-c-but-in-java-doesnt-some-puzzle
#define SWAP(x, y, T) 			do { T tmp = (x); (x) = (y); (y) = tmp; } while(0)
#define SORT2(a, b, T) 			do { if ((a) > (b)) SWAP((a), (b), T); } while (0)

#define foreach(i, n) 			for(unsigned int i = 0; i < (n); ++i)
#define foreach_range(i, s, e) 	for(unsigned int i = (s); i < (e); ++i)
#define foreach_arr(i, arr) 	for(unsigned int i = 0; i < ARRAY_SIZE(arr); ++i)
//  round robbin foreach,   从上一个指定的点开始，遍历,  h 是一个静态变量或全局变量，要记住上一次的位置。h 初始值是n !!!
#define foreach_hint(i, n, h) 	for(int i = 0, ++h, h=h<n?h:0; i < n; ++h, h=h<n?h:0)

#define ARRAY_SIZE(a) 			(sizeof(a) / sizeof(*a))

#define everyN(i, n) 			++(i); (i)=((i) < N ? (i) : 0); if(0 == (i))

#define U16_HI(a)    (((a) >> 8) & 0xFF)
#define U16_LO(a)    ((a) & 0xFF)

#define U32_BYTE0(a) ((a) & 0xFF)
#define U32_BYTE1(a) (((a) >> 8) & 0xFF)
#define U32_BYTE2(a) (((a) >> 16) & 0xFF)
#define U32_BYTE3(a) (((a) >> 24) & 0xFF)

#define HTON16(a)	((a >> 8) | ((a & 0xff) << 8))
#define HTON32(a)	((a >> 24) | (((a >> 16) & 0xff) << 8) | (((a >> 8) & 0xff) << 16) | ((a & 0xff) << 24))

/*********************************************************************
 * @fn          generateRandomNum
 *
 * @brief       generate random number
 *
 * @param       len - len
 *
 * @param       data -  buffer
 *
 * @return      None
 */
void generateRandomNum(int len, u8 *data);

void swapX(const u8 *src, u8 *dst, int len);
void swap16(u8 dst[2], const u8 src[2]);
void swap24(u8 dst[3], const u8 src[3]);
void swap32(u8 dst[4], const u8 src[4]);
void swap48(u8 dst[6], const u8 src[6]);
void swap56(u8 dst[7], const u8 src[7]);

void swap64(u8 dst[8], const u8 src[8]);

void swap128(u8 dst[16], const u8 src[16]);
u64 reverse_bit64(u64 src);

void net_store_16(u8 *buffer, u16 pos, u16 value);

void flip_addr(u8 *dest, u8 *src);

void store_16(u8 *buffer, u16 pos, u16 value);
void freeTimerTask(void **arg);


typedef	struct {
	u16		size;
	u8		num;
	u8		wptr;
	u8		rptr;
	u8*		p;
}	my_fifo_t;



typedef	struct {
	u16		len;
	u8		data[1];
}	my_fifo_buf_t;

void my_fifo_init (my_fifo_t *f, u8 s, u8 n, u8 *p);
u8* my_fifo_wptr (my_fifo_t *f);
void my_fifo_next (my_fifo_t *f);
int my_fifo_push (my_fifo_t *f, u8 *p, u16 n, u8 *head, u8 head_len);
void my_fifo_pop (my_fifo_t *f);
extern u8 * my_fifo_get (my_fifo_t *f);
void my_fifo_reset(my_fifo_t *f);
extern u8 my_fifo_data_cnt_get (my_fifo_t *f);
u8 my_fifo_free_cnt_get(my_fifo_t *f);

u8 * my_fifo_get_offset (my_fifo_t *f, u8 offset);

#define		MYFIFO_INIT(name,size,n)		u8 name##_b[(size) * (n)]={0};my_fifo_t name = {size,n,0,0,name##_b};  \
                                            STATIC_ASSERT(BIT_IS_POW2(n))
#define		MYFIFO_INIT_NO_RET(name,size,n)		_attribute_no_retention_bss_ u8 name##_b[(size) * (n)]={0};_attribute_no_retention_data_ my_fifo_t name = {size,n,0,0,name##_b};  \
												STATIC_ASSERT(BIT_IS_POW2(n))
#define		ATT_ALIGN4_DMA_BUFF(n)			(((n + 10) + 3) / 4 * 4)

